import { Request } from 'express'
import { Op, type InferAttributes, type WhereOptions } from 'sequelize'
import { NotFound, BadRequest, Unauthorized } from 'http-errors'
import bcrypt from 'bcryptjs'
import User from '@/database/models/user'
import { isEmpty } from '@/utils/tools'
import Role from '@/database/models/role'
import Order from '@/database/models/order'

const getUsers = async (query: Query) => {
  const pageNum = Math.abs(Number(query.pageNum)) || 1
  const pageSize = Math.abs(Number(query.pageSize)) || 10
  const offset = (pageNum - 1) * pageSize
  const where: WhereOptions<InferAttributes<User>> = {}
  if (query.email) {
    where.email = {
      [Op.eq]: query.email as string,
    }
  }
  if (query.username) {
    where.username = {
      [Op.eq]: query.username as string,
    }
  }
  if (query.nickname) {
    where.nickname = {
      [Op.like]: `%${query.nickname}%`,
    }
  }
  if (query.roleId) {
    where.roleId = {
      [Op.eq]: query.roleId as string,
    }
  }
  const { rows, count } = await User.findAndCountAll({
    ...getCondition(),
    where,
    // order: [['id', 'DESC']],
    attributes: { exclude: ['password', 'RoleId'] },
    limit: pageSize,
    offset,
  })
  return {
    users: rows,
    pagination: {
      total: count,
      pageNum,
      pageSize,
    },
  }
}

const getUserInfo = async (id: number) => {
  return await getUser(id)
}

const updateUserInfo = async (id: number, body: Body) => {
  const newBody = {
    nickname: body.nickname as string,
    gender: !isEmpty(body.gender) ? +body.gender : undefined,
    avatar: body.avatar as string,
  }
  const user = await getUser(id)
  await user.update(newBody)
  return user
}

const updateAccount = async (id: number, body: Body) => {
  const { email, username, current_password, password, password_confirmation } = body
  if (!current_password) {
    throw new BadRequest('当前密码必须填写')
  }
  if (password !== password_confirmation) {
    throw new BadRequest('两次输入的密码不一致')
  }
  const user = await getUser(id, true)
  // 验证当前密码是否正确
  const isPasswordValid = bcrypt.compareSync(current_password, user.password)
  if (!isPasswordValid) {
    throw new Unauthorized('当前密码不正确')
  }
  const newUser = await user.update({
    email: email,
    username: username,
    password: password,
  })
  return { ...newUser.dataValues, password: undefined }
}

/**
 * 公共方法：关联用户
 */
function getCondition() {
  return {
    include: [
      {
        model: Role,
        as: 'role',
        attributes: ['id', 'name', 'desc'],
      },
      // {
      //   model: Order,
      //   as: 'orders',
      //   attributes: { exclude: ['UserId'] },
      // },
    ],
  }
}

/**
 * 公共方法：查询当前用户
 */
async function getUser(id: number, showPassword = false) {
  const user = await User.findByPk(id, {
    ...getCondition(),
    attributes: { exclude: !showPassword ? ['password', 'RoleId'] : ['RoleId'] },
  })
  if (!user) {
    throw new NotFound(`ID:${id}的用户未找到。`)
  }
  return user
}

export default {
  getUsers,
  getUserInfo,
  updateUserInfo,
  updateAccount,
}
